import { UserInfo } from '@/typings'
import { UserTypes } from '../actions_types/actions_types'
import { ActionContext } from 'vuex'
import { RootState } from '@/store'

import {
  getToken,
  setToken,
  removeToken
} from '@/utils/auth'
import { userLogin, getUserInfo, userRegister, logout } from '@/api/index'
import { LoginPayload, RegisterType } from '@/typings/api'

type LOADING_TYPE = 'loading' | 'waring' | 'success'

// 状态值类型
export type UserState = {
  token: string
  userInfo: UserInfo
  globalLoading: boolean
  loading_type: LOADING_TYPE 
  message: string
  timer: number | null
  redirect: string
}

// 注册mutations中有那些方法
type Mutations<S = UserState> = {
  [UserTypes.SET_TOKEN](state: S, token: string): void
  [UserTypes.SET_LOADING](state: S, loading: boolean): void
  [UserTypes.SET_LOADING_TYPE](state: S, loading: LOADING_TYPE): void
  [UserTypes.SET_MESSAGE](state: S, loading: string): void
  [UserTypes.SET_REDIRECT](state: S, redirect: string): void
  [UserTypes.SET_USER_INFO](state: UserState, userInfo: UserInfo):void
}

type AugmentedActionContext = {
  commit<K extends keyof Mutations>(key: K, payload: Parameters<Mutations[K]>[1]): ReturnType<Mutations[K]>
} & Omit<ActionContext<UserState, RootState>, 'commit'>
  
const getState = (): UserState => { 
  return {
    token: getToken(),
    userInfo: {} as UserInfo,
    globalLoading: false,
    loading_type: 'loading',
    message: '加载中...',
    timer: null,
    redirect: ''
  }
}

const mutations = {
  // 设置用户token
  [UserTypes.SET_TOKEN]: (state: UserState, value: string) => { 
    setToken(value)
    state.token = value
  },
  // 设置加载状态
  [UserTypes.SET_LOADING]: (state: UserState, value: boolean) => { 
    state.globalLoading = value
    // 如果时隐藏加载框就将所有的加载信息重置为初始值
    if (!value) { 
      state.loading_type = 'loading'
      state.message = '加载中...'
    }
  },
  // 设置加载类型
  [UserTypes.SET_LOADING_TYPE]: (state: UserState, payload: LOADING_TYPE) => {
    state.loading_type = payload
    // 如果当前定时器已经存在就将定时器删除
    if (state.timer) { 
      clearTimeout(state.timer)
    }
    // 当类型为警告状态时重新开启定时器，1.5秒之后清除
    if (payload !== "loading") { 
      state.timer = setTimeout(() => {
        mutations[UserTypes.SET_LOADING](state, false)
       }, 2000)
    }
  },
  // 设置加载消息
  [UserTypes.SET_MESSAGE]: (state: UserState, payload: string) => {
    state.message = payload
  },
  // 设置重定向路由
  [UserTypes.SET_REDIRECT]: (state: UserState, payload: string) => { 
    state.redirect = payload
  },
  // 设置用户信息
  [UserTypes.SET_USER_INFO]: (state: UserState, userInfo: UserInfo) => {
    if (userInfo.avatar) { 
      userInfo.avatar = process.env.VUE_APP_BASE_DEV + userInfo.avatar
    }
    state.userInfo.avatar = userInfo.avatar
    state.userInfo.birthday = userInfo.birthday
    state.userInfo.create_date = userInfo.create_date
    state.userInfo.email = userInfo.email
    state.userInfo.id = userInfo.id
    state.userInfo.mobile = userInfo.mobile
    state.userInfo.nickname = userInfo.nickname
    state.userInfo.sex = userInfo.sex
    state.userInfo.update_date = userInfo.update_date
    state.userInfo.username = userInfo.username 
   }
}

const actions = {
  // 获取用户信息
  [UserTypes.GET_USER_INFO]: async (context: AugmentedActionContext): Promise<any> => {
    try { 
      const data = await getUserInfo()
      if (data.code === 0) {
        const res = data.data as UserInfo
        const payload = {
          username: res.username,
          update_date: res.update_date,
          sex: res.sex,
          nickname: res.nickname,
          mobile: res.mobile,
          id: res.id,
          email: res.email,
          create_date: res.create_date,
          birthday: res.birthday,
          avatar: res.avatar
        }
        context.commit(UserTypes.SET_USER_INFO, payload)
        context.commit(UserTypes.SET_LOADING, false)
        // 跳转到指定页面，如果又重定向直接重定向，否则跳转到首页
        const redirect = context.state.redirect
        const index = ['/pages/index/index', '/pages/cart/cart', '/pages/user/user',"/pages/bookshelf/bookshelf" ].indexOf(redirect)
        if (!redirect) {
          uni.switchTab({
            url: '/pages/index/index'
          })
        } else if (index >= 0) {
          uni.switchTab({
            url: redirect
          })
        } else { 
          uni.redirectTo({
            url: redirect
          })
        }
      } else { 
        context.commit(UserTypes.SET_LOADING_TYPE, 'waring')
        context.commit(UserTypes.SET_MESSAGE, data.message)
      }
    } catch (err) {
      console.log("获取用户信息err==>", err);
      context.commit(UserTypes.SET_MESSAGE, '请求失败<br>请检查网络')
      context.commit(UserTypes.SET_LOADING_TYPE, 'waring')
     }
   },
  // 登录
  [UserTypes.LOGIN]: async (context: AugmentedActionContext, payload: LoginPayload): Promise<any> =>{
    try {
      const data = await userLogin(payload)
      
      if (data.code === 0) {
        // 登录成功之后保存用户token并且获取用户信息
        context.commit(UserTypes.SET_TOKEN, data.data.token)
        context.dispatch(UserTypes.GET_USER_INFO)
      } else { 
        // 登录失败，提示失败信息
        context.commit(UserTypes.SET_MESSAGE, data.message)
        context.commit(UserTypes.SET_LOADING_TYPE, 'waring')
      }
    } catch (err) { 
      // 客户端错误
      console.log('err==>', err);
      context.commit(UserTypes.SET_MESSAGE, '登录失败<br>请检查网络')
      context.commit(UserTypes.SET_LOADING_TYPE, 'waring')
    }
  },
  // 退出登录
  [UserTypes.LOGOUT]: async ({ commit }: AugmentedActionContext, payload: {redirect: string}): Promise<any> => {
    try { 
      commit(UserTypes.SET_REDIRECT, payload.redirect)
      // 显示加载动画
      commit(UserTypes.SET_LOADING, true)
      // 发起请求退出登录，不管后端处理结果如何，默认退出登录成功
      await logout()
    } catch (err) {
      console.log('err==>', err);
    } finally { 
      commit(UserTypes.SET_TOKEN, '')
      removeToken()
      commit(UserTypes.SET_LOADING, false)
      uni.navigateTo({ url: '/pages/login/login?redirect='+ payload.redirect })
    }
    
  },
  // 注册
  [UserTypes.REGISTER]: async (context: AugmentedActionContext, payload: RegisterType): Promise<any> => { 
    try { 
      context.commit(UserTypes.SET_LOADING, true)
      const data = await userRegister(payload)
      if (data.code === 0) {
        // 登录成功之后保存用户token并且获取用户信息
        context.commit(UserTypes.SET_TOKEN, data.data.token)
        context.dispatch(UserTypes.GET_USER_INFO)
      } else { 
        context.commit(UserTypes.SET_MESSAGE, data.message)
        context.commit(UserTypes.SET_LOADING_TYPE, 'waring')
      }
    } catch (err) {
      console.log('err==>', err);
      context.commit(UserTypes.SET_MESSAGE, '注册失败<br>请检查网络')
      context.commit(UserTypes.SET_LOADING_TYPE, 'waring')
     }
  }
}


const state = getState()

export default {
  namespaced: true,
  state, 
  mutations,
  actions
}